package com.pokermind.dse.tcp.handler;

import com.pokermind.dse.tcp.config.TcpServerConfig;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Connection Handler
 * 连接管理处理器，负责连接的生命周期管理
 * 
 * 功能：
 * 1. 连接建立和断开管理
 * 2. 连接数量统计和限制
 * 3. 空闲连接检测和清理
 * 4. 连接监控指标记录
 * 
 * @author PokerMind Team
 */
@Component
@Sharable
public class ConnectionHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(ConnectionHandler.class);

    @Autowired
    private TcpServerConfig config;

    @Autowired
    private MeterRegistry meterRegistry;

    // 连接管理
    private final ConcurrentHashMap<String, ChannelHandlerContext> activeConnections = new ConcurrentHashMap<>();
    private final AtomicInteger connectionCount = new AtomicInteger(0);

    // 监控指标
    private Counter connectionsAccepted;
    private Counter connectionsRejected; 
    private Counter connectionsClosed;
    private Counter idleTimeouts;

    @PostConstruct
    public void initialize() {
        setupMetrics();
        logger.info("ConnectionHandler initialized - maxConnections: {}", 
                config.getServer().getMaxConnections());
        
        // 启动连接统计监控（每5分钟打印一次统计信息）
        startConnectionMonitoring();
    }
    
    /**
     * 启动连接统计监控
     */
    private void startConnectionMonitoring() {
        java.util.concurrent.Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "connection-monitor");
            t.setDaemon(true);
            return t;
        }).scheduleAtFixedRate(this::logConnectionStats, 5, 5, java.util.concurrent.TimeUnit.MINUTES);
    }
    
    /**
     * 记录连接统计信息
     */
    private void logConnectionStats() {
        int current = connectionCount.get();
        int max = config.getServer().getMaxConnections();
        double usage = (current * 100.0) / max;
        long accepted = (long) connectionsAccepted.count();
        long rejected = (long) connectionsRejected.count();
        long closed = (long) connectionsClosed.count();
        
        String usageStr = String.format("%.2f", usage);
        logger.info("Connection Stats: current={}, max={}, usage={}%, " +
                   "accepted={}, rejected={}, closed={}", 
                   current, max, usageStr, accepted, rejected, closed);
    }
    

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String clientId = getClientId(ctx);
        
        // 检查连接数量限制
        if (connectionCount.get() >= config.getServer().getMaxConnections()) {
            logger.warn("Connection rejected - max connections reached: {} from {}", 
                    config.getServer().getMaxConnections(), clientId);
            connectionsRejected.increment();
            ctx.close();
            return;
        }

        // 接受连接
        activeConnections.put(clientId, ctx);
        int currentCount = connectionCount.incrementAndGet();
        connectionsAccepted.increment();

        logger.info("Connection established: {} (total: {}, max: {})", 
                clientId, currentCount, config.getServer().getMaxConnections());

        // 存储客户端信息到Channel属性
        ctx.channel().attr(ClientAttributes.CLIENT_ID).set(clientId);
        ctx.channel().attr(ClientAttributes.CONNECT_TIME).set(System.currentTimeMillis());

        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String clientId = getClientId(ctx);
        
        // 移除连接
        if (activeConnections.remove(clientId) != null) {
            int currentCount = connectionCount.decrementAndGet();
            connectionsClosed.increment();
            
            // 计算连接持续时间
            Long connectTime = ctx.channel().attr(ClientAttributes.CONNECT_TIME).get();
            if (connectTime != null) {
                long duration = System.currentTimeMillis() - connectTime;
                logger.info("Connection closed: {} (duration: {}ms, total: {}, max: {})", 
                        clientId, duration, currentCount, config.getServer().getMaxConnections());
            } else {
                logger.info("Connection closed: {} (total: {}, max: {})", 
                        clientId, currentCount, config.getServer().getMaxConnections());
            }
        }

        super.channelInactive(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleEvent = (IdleStateEvent) evt;
            String clientId = getClientId(ctx);
            
            if (idleEvent.state() == IdleState.READER_IDLE) {
                logger.warn("Connection read idle timeout: {}", clientId);
            } else if (idleEvent.state() == IdleState.WRITER_IDLE) {
                logger.warn("Connection write idle timeout: {}", clientId);
            }
            
            idleTimeouts.increment();
            ctx.close(); // 关闭空闲连接
            return;
        }
        
        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        String clientId = getClientId(ctx);
        logger.error("Connection error for {}: {}", clientId, cause.getMessage(), cause);
        
        // 异常时关闭连接
        ctx.close();
    }

    /**
     * 获取客户端标识
     */
    private String getClientId(ChannelHandlerContext ctx) {
        if (ctx.channel() != null && ctx.channel().remoteAddress() != null) {
            return ctx.channel().remoteAddress().toString();
        }
        return "unknown";
    }

    /**
     * 设置监控指标
     */
    private void setupMetrics() {
        connectionsAccepted = Counter.builder("tcp.connections.accepted")
                .description("Number of accepted TCP connections")
                .register(meterRegistry);
                
        connectionsRejected = Counter.builder("tcp.connections.rejected") 
                .description("Number of rejected TCP connections")
                .register(meterRegistry);
                
        connectionsClosed = Counter.builder("tcp.connections.closed")
                .description("Number of closed TCP connections") 
                .register(meterRegistry);
                
        idleTimeouts = Counter.builder("tcp.connections.idle.timeouts")
                .description("Number of idle timeout closures")
                .register(meterRegistry);

        // 活跃连接数量指标
        Gauge.builder("tcp.connections.active", this, handler -> handler.connectionCount.get())
                .description("Number of active TCP connections")
                .register(meterRegistry);
    }

    /**
     * 获取连接统计信息
     */
    public ConnectionStats getConnectionStats() {
        return new ConnectionStats(
                connectionCount.get(),
                activeConnections.size(),
                config.getServer().getMaxConnections(),
                (long) connectionsAccepted.count(),
                (long) connectionsRejected.count(),
                (long) connectionsClosed.count(),
                (long) idleTimeouts.count()
        );
    }

    /**
     * 强制关闭指定客户端连接
     */
    public boolean closeConnection(String clientId) {
        ChannelHandlerContext ctx = activeConnections.get(clientId);
        if (ctx != null && ctx.channel().isActive()) {
            logger.info("Force closing connection: {}", clientId);
            ctx.close();
            return true;
        }
        return false;
    }

    /**
     * 获取所有活跃连接的客户端ID
     */
    public java.util.Set<String> getActiveClientIds() {
        return activeConnections.keySet();
    }

    // ===============================================
    // 内部类和常量
    // ===============================================

    /**
     * 客户端属性常量
     */
    public static class ClientAttributes {
        public static final io.netty.util.AttributeKey<String> CLIENT_ID = 
                io.netty.util.AttributeKey.valueOf("CLIENT_ID");
        public static final io.netty.util.AttributeKey<Long> CONNECT_TIME = 
                io.netty.util.AttributeKey.valueOf("CONNECT_TIME");
        public static final io.netty.util.AttributeKey<String> SESSION_ID = 
                io.netty.util.AttributeKey.valueOf("SESSION_ID");
    }

    /**
     * 连接统计信息
     */
    public static class ConnectionStats {
        private final int currentConnections;
        private final int activeConnections;
        private final int maxConnections;
        private final long totalAccepted;
        private final long totalRejected;
        private final long totalClosed;
        private final long totalIdleTimeouts;

        public ConnectionStats(int currentConnections, int activeConnections, int maxConnections,
                              long totalAccepted, long totalRejected, long totalClosed, long totalIdleTimeouts) {
            this.currentConnections = currentConnections;
            this.activeConnections = activeConnections;
            this.maxConnections = maxConnections;
            this.totalAccepted = totalAccepted;
            this.totalRejected = totalRejected;
            this.totalClosed = totalClosed;
            this.totalIdleTimeouts = totalIdleTimeouts;
        }

        // Getters
        public int getCurrentConnections() { return currentConnections; }
        public int getActiveConnections() { return activeConnections; }
        public int getMaxConnections() { return maxConnections; }
        public long getTotalAccepted() { return totalAccepted; }
        public long getTotalRejected() { return totalRejected; }
        public long getTotalClosed() { return totalClosed; }
        public long getTotalIdleTimeouts() { return totalIdleTimeouts; }

        @Override
        public String toString() {
            return String.format(
                    "ConnectionStats{current=%d, active=%d, max=%d, accepted=%d, rejected=%d, closed=%d, timeouts=%d}",
                    currentConnections, activeConnections, maxConnections, totalAccepted, totalRejected, totalClosed, totalIdleTimeouts
            );
        }
    }
}
